Code Should Be Obvious
「コードを明白にせよ」
コードが明白である
あまり考えずにコードを読むことができる
コードの動作や意味に関する最初の推測が正しいこと
不明瞭さが高いコードよりも、コメントが少ない
コードが明白でない(不明瞭)= Nonobvious Code
コードに関する必要な情報を集めるのに多くの時間や労力を費やす
作業効率が下がる
誤解やバグの可能性
レッドフラグ
コードが明白かどうかを判断する最良の方法 = コードレビュー
他人のコードのほうが設計上の問題を見つけやすい
自分のコードを読んだ誰かが「不明瞭だ」と言ったら、そのコードは明白でない
たとえ、自分には明白に見えてても
コードを明白にするテクニック
良い名前を選ぶ(Choosing Names)
コードの動作を明確にし、コメントの必要性を軽減する
一貫性(Consistency)
似たようなことを似たような方法で行うことで、読み手にパターンを認識させる
空白を適切に用いる
e.g. 関数パラメータのコメントを、パラメータの説明ごとに改行する
e.g. メソッド内のコードブロックを区切る
e.g. 文の構文を明確にする
コメント
不足している情報を提供する
Why Write Comments? The Four Exercisesradish-miyazaki.icon
ただし、読み手の立場に立って以下を考える必要がある
何が読み手を混乱させるか
どのような情報が、その混乱を解消するか
コードを不明瞭にする要素
イベント駆動型プログラミング
イベントが発生したら、ある1つのモジュールが他の部分にイベントが発生したことを通知する
e.g. マウスボタンの押下、パケットの到着
他の部分は、通知を受け取ったら、事前に指定された関数やメソッドを呼び出す
制御の流れを追ったり、理解したりするのが難しい
イベントハンドラ関数は直接呼び出されることはない
イベントモジュールが関数ポインタやインタフェースを用いて間接的に呼び出す
イベントモジュールの呼び出し箇所を見つけても、具体的にどの関数が呼び出されるか分からない
解決策: イベントモジュールのインタフェースのコメントで、いつ呼び出されるかを示す
code:java
/**
* This method is invoked in the dispatch thread by a transport if a
* transport-level error prevents an RPC from completing.
*/
void Transport::RpcNotifier::failed() {
...
}
汎用的なコンテナ
汎用的なコンテナとは、2つ以上の要素を1つのオブジェクトにまとめる汎用的なクラスのこと
e.g. Java の Pair や C++ の std::pair
code:java
return new Pair<Integer, Boolean>(currentTerm, false);
各要素がどのような意味を持つのか不明瞭
上記の例だと、 result.getKey() と result.getValue() で参照する必要があるが、これでは値の持つ意味が分からない
解決策: 汎用的なコンテナは使わず、特定の用途に特化した新しいクラスを定義する
要素に意味のある名前を付ける
コメントで情報を補足することも可能
宣言と実際の型が異なる
e.g.
code:java
private List<Message> incomingMessageList;
...
incomingMessageList = new ArrayList<Message>();
変数は List として宣言されているが実際の値は ArrayList
List は ArrayList のスーパークラスなのでコンパイルは通る
List と ArrayList では扱い方が異なるので、読み手に誤解を与え得る
Java の ArrayList は、List の他のサブクラスと異なるパフォーマンスとスレッドセーフの特性を持っている
解決策: 宣言と実際の型は一致させる
読者の期待に反するコード
驚き最小の原則
e.g.
code:java
public static void main(String[] args) {
...
new RaftClient(myAddress, serverAddresses);
}
通常、メインプログラムが return するとアプリケーションは終了する
しかし上記のコードでは、RaftClient コンストラクタは追加のスレッドを作成し、アプリケーションのメインスレッドが終了しても動作し続ける
解決策: 読み手が期待しない挙動の場合、コメントで補足する
e.g. RaftClient コンストラクタのインタフェース or new RaftClient(...) の直前にアプリケーションが他のスレッドで実行することを記述する
hr.icon
要約
コードが明白である = そのコードに関する重要な情報を常に読み手が持っている
コードが明白でない = そのコードに関する重要な情報を読み手が持っていない
コードを明白にする3つの方法
抽象化 や特殊なケースを排除するなど、設計のテクニックを用いて必要な情報を減らす
読み手が既知の情報を活用する(慣習に沿う、期待通りの挙動をする etc...)
コード内で必要な情報を示す(良い名前やコメントを付ける etc...)
#読書メモ